﻿using RestSharp;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Data.Entity.Validation;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ServiceProcess;
using System.Timers;
using thousandClear;
using thousandClear.Util.Logging;
using thousandclear.Data;

namespace thousandClear.Batch
{
    partial class AccessTokenRefreshService : ServiceBase
    {
        private ILogger _logger;

        private int _interval;
        private Timer _timer = null;
        private string _appId = string.Empty;
        private string _appSecret = string.Empty;
        private string _corpId = string.Empty;
        private string _corpSecret = string.Empty;
        private qianjingEntities _db = null;
        private AccessToken _appAccessToken = null;
        private AccessToken _corpAccessToken = null;


        public AccessTokenRefreshService()
        {
            InitializeComponent();

            _logger = new LoggerFactory().SetCurrent(new Log4NetLoggerFactory("Wechat_AccessToken")).CreateLogger();

            _interval = int.Parse(ConfigurationManager.AppSettings["AccessTokenRefresh_Interval"]);
            _appId = ConfigurationManager.AppSettings["WeiXin_AppId"];
            _appSecret = ConfigurationManager.AppSettings["WeiXin_AppSecret"];
            _corpId = ConfigurationManager.AppSettings["WeiXin_CorpId"];
            _corpSecret = ConfigurationManager.AppSettings["WeiXin_CorpSecret"];
            _timer = new Timer(_interval);
            _timer.Elapsed += timer_Elapsed;
        }

        private void timer_Elapsed(object sender, ElapsedEventArgs e)
        {
            _logger.Debug("====================[Stop]AccessTokenRefreshService - TimerElapsed====================");

            _logger.Debug(string.Format("**********Interval: {0} s", _interval / 1000));
            

            _logger.Debug("--------------------[Start]AccessTokenRefreshService - GetAppAccessToken--------------------");

            try
            {
                _appAccessToken = GetAppAccessToken();
            }
            catch (Exception ex)
            {
                var exceptionId = Guid.NewGuid().ToString();
                _logger.Debug(string.Format("**********ExceptionId: {0}", exceptionId));
                _logger.Debug(string.Format("[{0}]AccessTokenRefreshService - GetAppAccessToken", exceptionId), ex);
            }

            _logger.Debug("--------------------[Stop]AccessTokenRefreshService - GetAppAccessToken---------------------");

            

            _logger.Debug("--------------------[Start]AccessTokenRefreshService - GetCorpAccessToken--------------------");

            try
            {
                _corpAccessToken = GetCorpAccessToken();
            }
            catch (Exception ex)
            {
                var exceptionId = Guid.NewGuid().ToString();

                _logger.Debug(string.Format("**********ExceptionId: {0}", exceptionId));

                _logger.Debug(string.Format("[{0}]AccessTokenRefreshService - GetCorpAccessToken", exceptionId), ex);
            }

            _logger.Debug("--------------------[Stop]AccessTokenRefreshService - GetCorpAccessToken--------------------");


            using (_db = new qianjingEntities())
            {
                _logger.Debug("--------------------[Start]AccessTokenRefreshService - RefreshAppAccessToken--------------------");

                try
                {
                    RefreshAccessToken(_db, "app_access_token", _appAccessToken.access_token, DateTime.Now.AddSeconds(_appAccessToken.expires_in));
                    _db.SaveChanges();
                }
                catch (Exception ex)
                {
                    var exceptionId = Guid.NewGuid().ToString();

                    _logger.Debug(string.Format("**********ExceptionId: {0}", exceptionId));

                    _logger.Debug(string.Format("[{0}]AccessTokenRefreshService - RefreshAppAccessToken", exceptionId), ex);
                }
                _logger.Debug("--------------------[Stop]AccessTokenRefreshService - RefreshAppAccessToken--------------------");

                _logger.Debug("--------------------[Start]AccessTokenRefreshService - RefreshCorpAccessToken--------------------");

                try
                {
                    RefreshAccessToken(_db, "corp_access_token", _corpAccessToken.access_token, DateTime.Now.AddSeconds(_corpAccessToken.expires_in));
                    _db.SaveChanges();
                }
                catch (Exception ex)
                {
                    var exceptionId = Guid.NewGuid().ToString();

                    _logger.Debug(string.Format("**********ExceptionId: {0}", exceptionId));

                    _logger.Debug(string.Format("[{0}]AccessTokenRefreshService - RefreshCorpAccessToken", exceptionId), ex);
                }
                _logger.Debug("--------------------[Stop]AccessTokenRefreshService - RefreshCorpAccessToken--------------------");

            }

            _logger.Debug("====================[Stop]AccessTokenRefreshService - TimerElapsed====================");
        }

        protected override void OnStart(string[] args)
        {
            log4net.Config.XmlConfigurator.Configure();

            _timer.Start();
            _logger.Debug("--------------------[Start]AccessTokenRefreshService--------------------");

        }

        protected override void OnStop()
        {
            _timer.Stop();
            _logger.Debug("--------------------[Stop]AccessTokenRefreshService Stop--------------------");
        }

        private class AccessToken
        {
            public string access_token { get; set; }
            public int expires_in { get; set; }
        }

        private AccessToken GetAppAccessToken()
        {
            var client = new RestClient("https://api.weixin.qq.com/cgi-bin");

            AccessToken accessToken = null;

            var request = new RestRequest("token?grant_type=client_credential&appid={appid}&secret={appsecret}", Method.GET);
            request.AddUrlSegment("appid", _appId);
            request.AddUrlSegment("appsecret", _appSecret);

            _logger.Debug(string.Format("**********Appid: {0}", _appId));
            _logger.Debug(string.Format("**********AppSecret: {0}", _appSecret));

            var resp = client.Execute<AccessToken>(request);

            _logger.Debug(string.Format("**********Response: {0}", resp.Content));


            accessToken = resp.Data;

            _logger.Debug(string.Format("**********AppAccessToken: {0}", accessToken.access_token));
            _logger.Debug(string.Format("**********AppExpiresIn: {0} s", accessToken.expires_in));


            return accessToken;
        }

        private AccessToken GetCorpAccessToken()
        {
            var client = new RestClient("https://qyapi.weixin.qq.com/cgi-bin");

            AccessToken accessToken = null;

            var request = new RestRequest("gettoken?corpid={corpid}&corpsecret={corpsecret}", Method.GET);
            request.AddUrlSegment("corpid", _corpId);
            request.AddUrlSegment("corpsecret", _corpSecret);

            _logger.Debug(string.Format("**********CorpId: {0}", _corpId));
            _logger.Debug(string.Format("**********CorpSecret: {0}", _corpSecret));

            var resp = client.Execute<AccessToken>(request);

            _logger.Debug(string.Format("**********Response: {0}", resp.Content));

            accessToken = resp.Data;

            _logger.Debug(string.Format("**********CorpAccessToken: {0}", accessToken.access_token));
            _logger.Debug(string.Format("**********CorpExpiresIn: {0} s", accessToken.expires_in));

            return accessToken;
        }

        private void RefreshAccessToken(qianjingEntities dbContext, string code, string value, DateTime expiredTime)
        {
            var record = dbContext.D_metaData.FirstOrDefault(a => a.Code == code);

            if (record != null)
            {
                record.Value = value;
                record.ExpiredTime = expiredTime;
                record.UpdatedTime = DateTime.Now;
                record.Version = DateTime.Now.Ticks;
            }
            else
            {
                record = new D_metaData();
                record.Code = code;
                record.Value = value;
                record.ExpiredTime = expiredTime;
                record.CreatedTime = DateTime.Now;
                record.UpdatedTime = DateTime.Now;
                record.Version = DateTime.Now.Ticks;

                dbContext.D_metaData.Add(record);
            }
        }
    }
}
